﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using SP.FeatureAdministrationTool.Extensions;
using SP.FeatureAdministrationTool.FeatureManagerModule;
using SP.FeatureAdministrationTool.WebApplicationModule;
using SP.FeatureAdministrationTool.SiteCollectionModule;
using SP.FeatureAdministrationTool.SiteModule;
using SP.FeatureAdministrationTool.Resources;
using System.Drawing;

namespace SP.FeatureAdministrationTool
{
    public partial class FeatureManagementForm : Form
    {
        public FeatureManagementForm()
        {
            this.SetStyle(ControlStyles.DoubleBuffer, true);
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            this.SetStyle(ControlStyles.UserPaint, true);
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.UpdateStyles();
            InitializeComponent();
            this.InitializeLocalizedResources();
        }

        private void FeatureManagementForm_Load(object sender, EventArgs e)
        {
            this.LoadFarmFeature(false);
            this.InitWebApplicationCombobox();
            this.CheckInvalidFeature();
        }

        protected override void OnShown(EventArgs e)
        {
            base.OnShown(e);
            SplashScreen.EndDisplay();
        }

        private void InitializeLocalizedResources()
        {
            this.Text = CommonUI.FormTitle;
            this.FarmFeatureTabPage.Text = CommonUI.TabTitle_FarmFeature;
            this.WebApplicationFeatureTabPage.Text = CommonUI.TabTitle_WebApplicationFeature;
            this.SiteCollectionFeatureTabPage.Text = CommonUI.TabTitle_SiteCollectionFeature;
            this.InvalidFeatureTabPage.Text = CommonUI.TabTitle_InvalidFeature;
            this.FarmFeatureTitleHeader.Text = CommonUI.TableHeader_FeatureTitle;
            this.FarmFeatureDisplayNameHeader.Text = CommonUI.TableHeader_DisplayName;
            this.FarmFeatureIdHeader.Text = CommonUI.TableHeader_FeatureId;
            this.FarmFeatureStatusHeader.Text = CommonUI.TableHeader_Status;
            this.WebApplicationFeatureTitleHeader.Text = CommonUI.TableHeader_FeatureTitle;
            this.WebApplicationFeatureDisplayNameHeader.Text = CommonUI.TableHeader_DisplayName;
            this.WebApplicationFeatureIdHeader.Text = CommonUI.TableHeader_FeatureId;
            this.WebApplicationFeatureStatusHeader.Text = CommonUI.TableHeader_Status;
            this.SiteCollectionFeatureTitleHeader.Text = CommonUI.TableHeader_FeatureTitle;
            this.SiteCollectionFeatureDisplayNameHeader.Text = CommonUI.TableHeader_DisplayName;
            this.SiteCollectionFeatureIdHeader.Text = CommonUI.TableHeader_FeatureId;
            this.SiteCollectionFeatureStatusHeader.Text = CommonUI.TableHeader_Status;
            this.InvalidFeatureTitleHeader.Text = CommonUI.TableHeader_FeatureTitle;
            this.InvalidFeatureDisplayNameHeader.Text = CommonUI.TableHeader_DisplayName;
            this.InvalidFeatureIdHeader.Text = CommonUI.TableHeader_FeatureId;
            this.InvalidFeatureStatusHeader.Text = CommonUI.TableHeader_Status;
            this.SelectWebApplicationLabel.Text = CommonUI.Label_SelectWebApplicaton;
            this.SC_SelectWebApplicationLabel.Text = CommonUI.Label_SelectWebApplicaton;
            this.SC_SelectSiteCollectionLabel.Text = CommonUI.Label_SelectSiteCollection;
            this.SC_SelectSiteLabel.Text = CommonUI.Label_SelectSite;
            this.ActivateFarmFeatureButton.Text = CommonUI.ButtonText_Activate;
            this.DeactivateFarmFeatureButton.Text = CommonUI.ButtonText_Deactivate;
            this.UninstallFarmFeatureButton.Text = CommonUI.ButtonText_Uninstall;
            this.ActivateWebApplicationFeatureButton.Text = CommonUI.ButtonText_Activate;
            this.DeactivateWebApplicationFeatureButton.Text = CommonUI.ButtonText_Deactivate;
            this.UninstallWebApplicationFeatureButton.Text = CommonUI.ButtonText_Uninstall;
            this.ActivateSiteCollectionFeatureButton.Text = CommonUI.ButtonText_Activate;
            this.DeacivateSiteCollectionFeatureButton.Text = CommonUI.ButtonText_Deactivate;
            this.UninstallSiteCollectionFeatureButton.Text = CommonUI.ButtonText_Uninstall;
            this.UninstallInvalidFeatureButton.Text = CommonUI.ButtonText_Uninstall;
            this.RefreshButton.Text = CommonUI.ButtonText_Refresh;
        }

        //private int CalculateSiteAmountInFarm()
        //{
        //    int amount = 0;
        //    foreach (SPWebApplication webApp in this.GetAllApplications())
        //    {
        //        try
        //        {
        //            amount += webApp.Sites.Count;
        //        }
        //        catch
        //        {
        //        }
        //    }

        //    return amount;
        //}

        private void InitWebApplicationCombobox()
        {
            List<WebApplication> allWebApps = WebApplicationManager.GetAllApplications();

            foreach (WebApplication webApp in allWebApps)
            {
                ComboBoxItem item = new ComboBoxItem(webApp.ToString())
                {
                    Id = webApp.Id
                };

                this.WebApplicationComboBox.Items.Add(item);
                this.SC_WebApplictionComboBox.Items.Add(item);
            }
        }

        private void RunWithSplashScreen(Action action)
        {
            SplashScreen.BeginDisplay();
            try
            {
                action();
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                SplashScreen.EndDisplay();
            }
        }

        private void DeactivateWebFeature(SPWeb web, Guid featureId)
        {
            try
            {
                web.Features.Remove(featureId, true);
            }
            catch
            {
            }

            if (web.Webs.Count > 0)
            {
                foreach (SPWeb subWeb in web.Webs)
                {
                    try
                    {
                        this.DeactivateWebFeature(subWeb, featureId);
                    }
                    catch
                    {
                    }
                    finally
                    {
                        subWeb.Dispose();
                    }
                }
            }
        }

        /// <summary>
        /// It's a no use method that for reference only, and will be remove in a later version.
        /// </summary>
        /// <param name="featureId"></param>
        private void UninstallFeature(Guid featureId)
        {
            try
            {
                //// Try to deactivate the feature first
                List<SPWebApplication> allWebApps = SPFarm.Local.GetAllWebApplications();
                SPFeatureDefinition featureDefinition = SPFarm.Local.FeatureDefinitions[featureId];
                switch (featureDefinition.Scope)
                {
                    case SPFeatureScope.Farm:
                        SPWebService.AdministrationService.Features.Remove(featureId);
                        break;

                    case SPFeatureScope.WebApplication:
                        foreach (SPWebApplication webApp in allWebApps)
                        {
                            try
                            {
                                webApp.Features.Remove(featureId);
                            }
                            catch
                            {
                            }
                        }

                        break;

                    case SPFeatureScope.Site:
                        foreach (SPWebApplication webApp in allWebApps)
                        {
                            try
                            {
                                foreach (SPSite site in webApp.Sites)
                                {
                                    try
                                    {
                                        site.Features.Remove(featureId);
                                    }
                                    catch
                                    {
                                    }
                                    finally
                                    {
                                        site.Dispose();
                                    }
                                }
                            }
                            catch
                            {
                            }
                        }

                        break;

                    case SPFeatureScope.Web:
                        foreach (SPWebApplication webApp in allWebApps)
                        {
                            try
                            {
                                foreach (SPSite site in webApp.Sites)
                                {
                                    try
                                    {
                                        this.DeactivateWebFeature(site.RootWeb, featureId);
                                    }
                                    catch
                                    {
                                    }
                                    finally
                                    {
                                        site.Dispose();
                                    }
                                }
                            }
                            catch
                            {
                            }
                        }

                        break;

                    default:
                        break;
                }
            }
            catch
            {
            }

            SPFarm.Local.FeatureDefinitions.Remove(featureId, true);
        }

        private void ShowWarningMessageBox(string message)
        {
            MessageBox.Show(message, CommonUI.MessageTitle_Warning, MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }

        private bool ConfirmUninstall()
        {
            if (MessageBox.Show(CommonUI.Message_Question_UnistallFeature,
                string.Empty,
                MessageBoxButtons.YesNo,
                MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
            {
                return true;
            }

            return false;
        }

        private ListViewItem MakeListViewItem(Feature feature)
        {
            return new ListViewItem(new string[] { feature.Title, feature.DisplayName, feature.Id.ToString(), feature.Hidden.ToString(), feature.Status.ToString() })
            {
                Tag = feature.Id
            };
        }

        #region Farm Feature

        private void LoadFarmFeature(bool showHidden)
        {
            this.FarmFeatureListView.Items.Clear();
            FeatureManager manager = new FarmFeatureManager();
            foreach (Feature feature in manager.GetAllFeatures())
            {
                if (showHidden || !feature.Hidden)
                {
                    this.FarmFeatureListView.Items.Add(this.MakeListViewItem(feature));
                }
            }
        }

        private void DeactivateFarmFeatureButton_Click(object sender, EventArgs e)
        {
            if (this.FarmFeatureListView.CheckedItems.Count <= 0)
            {
                return;
            }

            FeatureManager manager = new FarmFeatureManager();
            foreach (ListViewItem item in this.FarmFeatureListView.CheckedItems)
            {
                try
                {
                    Guid featureId = (Guid)item.Tag;
                    manager.DeactivateFeature(featureId);
                    item.SubItems[this.FarmFeatureStatusHeader.DisplayIndex].Text = FeatureActivationStatus.Deactivated.ToString();
                }
                catch (Exception ex)
                {
                    this.ShowWarningMessageBox(ex.Message);
                }
            }
        }

        private void ActivateFarmFeatureButton_Click(object sender, EventArgs e)
        {
            if (this.FarmFeatureListView.CheckedItems.Count <= 0)
            {
                return;
            }

            FeatureManager manager = new FarmFeatureManager();
            foreach (ListViewItem item in this.FarmFeatureListView.CheckedItems)
            {
                try
                {
                    Guid featureId = (Guid)item.Tag;
                    manager.ActivateFeature(featureId);
                    item.SubItems[this.FarmFeatureStatusHeader.DisplayIndex].Text = FeatureActivationStatus.Activated.ToString();
                }
                catch (Exception ex)
                {
                    this.ShowWarningMessageBox(ex.Message);
                }
            }
        }

        private void UninstallFarmFeatureButton_Click(object sender, EventArgs e)
        {
            if (this.FarmFeatureListView.CheckedItems.Count <= 0 || !this.ConfirmUninstall())
            {
                return;
            }

            FeatureManager manager = new FarmFeatureManager();
            foreach (ListViewItem item in this.FarmFeatureListView.CheckedItems)
            {
                try
                {
                    Guid featureId = new Guid(item.SubItems[this.FarmFeatureIdHeader.DisplayIndex].Text);
                    manager.DeactivateFeature(featureId);
                    FeatureManager.UninstallFeature(featureId);
                    this.FarmFeatureListView.Items.Remove(item);
                }
                catch (Exception ex)
                {
                    this.ShowWarningMessageBox(ex.Message);
                }
            }
        }

        #endregion

        #region Web Application Feature

        private WebApplicationFeatureManager GetWebApplicationFeatureManager()
        {
            ComboBoxItem item = (ComboBoxItem)this.WebApplicationComboBox.SelectedItem;

            return new WebApplicationFeatureManager(item.Id);
        }

        private void WebApplicationComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {

            this.LoadWebApplicationFeatures(this.ShowHiddenWebApplicationFeatureCheckBox.Checked);
        }

        private void LoadWebApplicationFeatures(bool showHidden)
        {
            this.WebApplicationFeatureListView.Items.Clear();
            if (this.WebApplicationComboBox.SelectedIndex == -1)
            {
                return;
            }

            this.RunWithSplashScreen(delegate()
            {
                FeatureManager manager = this.GetWebApplicationFeatureManager();
                foreach (Feature feature in manager.GetAllFeatures())
                {
                    if (showHidden || !feature.Hidden)
                    {
                        this.WebApplicationFeatureListView.Items.Add(this.MakeListViewItem(feature));
                    }
                }
            });
        }

        private void ActivateWebApplicationFeatureButton_Click(object sender, EventArgs e)
        {
            if (this.WebApplicationFeatureListView.CheckedItems.Count <= 0)
            {
                return;
            }

            FeatureManager manager = this.GetWebApplicationFeatureManager();
            foreach (ListViewItem item in this.WebApplicationFeatureListView.CheckedItems)
            {
                try
                {
                    Guid featureId = (Guid)item.Tag;
                    manager.ActivateFeature(featureId);
                    item.SubItems[this.WebApplicationFeatureStatusHeader.DisplayIndex].Text = FeatureActivationStatus.Activated.ToString();
                }
                catch (Exception ex)
                {
                    this.ShowWarningMessageBox(ex.Message);
                }
            }
        }

        private void DeactivateWebApplicationFeatureButton_Click(object sender, EventArgs e)
        {
            if (this.WebApplicationFeatureListView.CheckedItems.Count <= 0)
            {
                return;
            }

            FeatureManager manager = this.GetWebApplicationFeatureManager();
            foreach (ListViewItem item in this.WebApplicationFeatureListView.CheckedItems)
            {
                try
                {
                    Guid featureId = (Guid)item.Tag;
                    manager.DeactivateFeature(featureId);
                    item.SubItems[this.WebApplicationFeatureStatusHeader.DisplayIndex].Text = FeatureActivationStatus.Deactivated.ToString();
                }
                catch (Exception ex)
                {
                    this.ShowWarningMessageBox(ex.Message);
                }
            }
        }

        private void UninstallWebApplicationFeatureButton_Click(object sender, EventArgs e)
        {
            if (this.WebApplicationFeatureListView.CheckedItems.Count <= 0 || !this.ConfirmUninstall())
            {
                return;
            }

            FeatureManager manager = this.GetWebApplicationFeatureManager();
            foreach (ListViewItem item in this.WebApplicationFeatureListView.CheckedItems)
            {
                try
                {
                    Guid featureId = (Guid)item.Tag;
                    manager.DeactivateFeature(featureId);
                    FeatureManager.UninstallFeature(featureId);
                    this.WebApplicationFeatureListView.Items.Remove(item);
                }
                catch (Exception ex)
                {
                    this.ShowWarningMessageBox(ex.Message);
                }
            }
        }

        #endregion

        #region Site Collection Feature

        private void SC_WebApplictionComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.SC_SiteCollectionComboBox.Items.Clear();
            this.SC_WebsComboBox.Items.Clear();
            this.SiteCollectionFeatureListView.Items.Clear();
            if (this.SC_WebApplictionComboBox.SelectedIndex == -1)
            {
                return;
            }

            this.RunWithSplashScreen(delegate()
            {
                ComboBoxItem selectedApp = (ComboBoxItem)this.SC_WebApplictionComboBox.SelectedItem;
                List<SiteCollection> siteCollections = SiteCollectionManager.GetSiteCollections(selectedApp.Id);
                foreach (SiteCollection site in siteCollections)
                {
                    ComboBoxItem item = new ComboBoxItem(site.ToString())
                    {
                        Id = site.Id
                    };

                    this.SC_SiteCollectionComboBox.Items.Add(item);
                }
            });
        }

        private SiteCollectionFeatureManager GetSiteCollectionFeatureManager()
        {
            ComboBoxItem selectedSiteCollection = (ComboBoxItem)this.SC_SiteCollectionComboBox.SelectedItem;

            return new SiteCollectionFeatureManager(selectedSiteCollection.Id);
        }

        private void SC_SiteCollectionComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.LoadSiteCollectionFeatures(this.ShowHiddenSiteFeatureCheckBox.Checked);
        }

        private void LoadSiteCollectionFeatures(bool showHidden)
        {
            this.SiteCollectionFeatureListView.Items.Clear();
            this.SC_WebsComboBox.Items.Clear();
            if (this.SC_SiteCollectionComboBox.SelectedIndex == -1)
            {
                return;
            }

            this.RunWithSplashScreen(delegate()
            {
                FeatureManager manager = this.GetSiteCollectionFeatureManager();
                foreach (Feature feature in manager.GetAllFeatures())
                {
                    if (showHidden || !feature.Hidden)
                    {
                        this.SiteCollectionFeatureListView.Items.Add(this.MakeListViewItem(feature));
                    }
                }

                ComboBoxItem selectedSite = (ComboBoxItem)this.SC_SiteCollectionComboBox.SelectedItem;
                List<Site> sites = SiteManager.GetSites(selectedSite.Id);
                foreach (Site site in sites)
                {
                    this.SC_WebsComboBox.Items.Add(new ComboBoxItem(site.Title)
                    {
                        Id = site.Id
                    });
                }
            });
        }

        private void SC_WebsComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.LoadSiteFeatures(this.ShowHiddenSiteFeatureCheckBox.Checked);
        }

        private void LoadSiteFeatures(bool showHidden)
        {
            this.SiteCollectionFeatureListView.Items.Clear();
            if (this.SC_WebsComboBox.SelectedIndex == -1)
            {
                return;
            }

            this.RunWithSplashScreen(delegate()
            {
                FeatureManager manager = this.GetSiteFeatureManager();
                foreach (Feature feature in manager.GetAllFeatures())
                {
                    if (showHidden || !feature.Hidden)
                    {
                        this.SiteCollectionFeatureListView.Items.Add(this.MakeListViewItem(feature));
                    }
                }
            });
        }

        private SiteFeatureManager GetSiteFeatureManager()
        {
            ComboBoxItem selectedSiteCollection = (ComboBoxItem)this.SC_SiteCollectionComboBox.SelectedItem;
            ComboBoxItem selectedSite = (ComboBoxItem)this.SC_WebsComboBox.SelectedItem;

            return new SiteFeatureManager(selectedSiteCollection.Id, selectedSite.Id);
        }

        private bool IsSiteFeatureSelected()
        {
            return this.SC_WebsComboBox.SelectedIndex != -1;
        }

        private void ActivateSiteCollectionFeatureButton_Click(object sender, EventArgs e)
        {
            if (this.SiteCollectionFeatureListView.CheckedItems.Count <= 0)
            {
                return;
            }

            FeatureManager manager;
            if (this.IsSiteFeatureSelected())
            {
                manager = this.GetSiteFeatureManager();
            }
            else
            {
                manager = this.GetSiteCollectionFeatureManager();
            }

            foreach (ListViewItem item in this.SiteCollectionFeatureListView.CheckedItems)
            {
                try
                {
                    Guid featureId = (Guid)item.Tag;
                    manager.ActivateFeature(featureId);
                    item.SubItems[this.SiteCollectionFeatureStatusHeader.DisplayIndex].Text = FeatureActivationStatus.Activated.ToString();
                }
                catch (Exception ex)
                {
                    this.ShowWarningMessageBox(ex.Message);
                }
            }
        }

        private void DeacivateSiteCollectionFeatureButton_Click(object sender, EventArgs e)
        {
            if (this.SiteCollectionFeatureListView.CheckedItems.Count <= 0)
            {
                return;
            }

            FeatureManager manager;
            if (this.IsSiteFeatureSelected())
            {
                manager = this.GetSiteFeatureManager();
            }
            else
            {
                manager = this.GetSiteCollectionFeatureManager();
            }

            foreach (ListViewItem item in this.SiteCollectionFeatureListView.CheckedItems)
            {
                try
                {
                    Guid featureId = (Guid)item.Tag;
                    manager.DeactivateFeature(featureId);
                    item.SubItems[this.SiteCollectionFeatureStatusHeader.DisplayIndex].Text = FeatureActivationStatus.Deactivated.ToString();
                }
                catch (Exception ex)
                {
                    this.ShowWarningMessageBox(ex.Message);
                }
            }
        }

        private void UninstallSiteCollectionFeatureButton_Click(object sender, EventArgs e)
        {
            if (this.SiteCollectionFeatureListView.CheckedItems.Count <= 0 || !this.ConfirmUninstall())
            {
                return;
            }

            FeatureManager manager;
            if (this.IsSiteFeatureSelected())
            {
                manager = this.GetSiteFeatureManager();
            }
            else
            {
                manager = this.GetSiteCollectionFeatureManager();
            }

            foreach (ListViewItem item in this.SiteCollectionFeatureListView.CheckedItems)
            {
                try
                {
                    Guid featureId = (Guid)item.Tag;
                    manager.DeactivateFeature(featureId);
                    FeatureManager.UninstallFeature(featureId);
                    this.SiteCollectionFeatureListView.Items.Remove(item);
                }
                catch (Exception ex)
                {
                    this.ShowWarningMessageBox(ex.Message);
                }
            }
        }

        #endregion

        #region Invalid Feature

        private void CheckInvalidFeature()
        {
            this.InvalidFeatureListView.Items.Clear();
            System.Collections.Generic.Dictionary<Feature, Exception> invalidFeatures = FeatureManager.GetInvalidFeatures();
            foreach (Feature feature in invalidFeatures.Keys)
            {
                this.InvalidFeatureListView.Items.Add(this.MakeListViewItem(feature));
            }

            if (this.InvalidFeatureListView.Items.Count > 0)
            {
                this.InvalidFeatureTabPage.Text = string.Format("*{0}", CommonUI.TabTitle_InvalidFeature);
            }
        }

        private void UninstallInvalidFeatureButton_Click(object sender, EventArgs e)
        {
            if (this.InvalidFeatureListView.CheckedItems.Count <= 0 || !this.ConfirmUninstall())
            {
                return;
            }

            foreach (ListViewItem item in this.InvalidFeatureListView.CheckedItems)
            {
                try
                {
                    Guid featureId = (Guid)item.Tag;
                    FeatureManager.UninstallFeature(featureId);
                    this.InvalidFeatureListView.Items.Remove(item);
                }
                catch (Exception ex)
                {
                    this.ShowWarningMessageBox(ex.Message);
                }
            }

            if (this.InvalidFeatureListView.Items.Count == 0)
            {
                this.InvalidFeatureTabPage.Text = CommonUI.TabTitle_InvalidFeature;
            }
        }

        #endregion

        private void ListView_MouseClick(object sender, MouseEventArgs e)
        {
            ListView listView = sender as ListView;
            if (listView != null
                && listView.SelectedItems.Count > 0
                && e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                ListViewItem item = listView.SelectedItems[0];
                item.Checked = !item.Checked;
                listView.SelectedItems.Clear();
            }
        }

        private void RefreshButton_Click(object sender, EventArgs e)
        {
            this.RunWithSplashScreen(delegate()
            {
                this.CheckInvalidFeature();
            });
        }

        private void ShowHiddenFarmFeatureCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            CheckBox checkBox = sender as CheckBox;
            this.LoadFarmFeature(checkBox.Checked);
        }

        private void ShowHiddenWebApplicationFeatureCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            CheckBox checkBox = sender as CheckBox;
            this.LoadWebApplicationFeatures(checkBox.Checked);
        }

        private void ShowHiddenSiteFeatureCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            CheckBox checkBox = sender as CheckBox;
            if (this.IsSiteFeatureSelected())
            {
                this.LoadSiteFeatures(checkBox.Checked);
            }
            else
            {
                this.LoadSiteCollectionFeatures(checkBox.Checked);
            }
        }

        private void ListView_ItemChecked(object sender, ItemCheckedEventArgs e)
        {
            if (e.Item != null)
            {
                e.Item.ForeColor = e.Item.Checked ? Color.Blue : SystemColors.ControlText;
            }
        }
    }
}
